const async = require('async');
//{ one: 1, two: 2 }
const tasks = {
  one: function(callback){
      callback(null, 1);
  },
  two: function(callback){
      callback(null, 2);
  }
}
//[ 1, 2 ]
const tasks1 = [
  function(callback){
         callback(null, 1);
     },
   function(callback){
         callback(null, 2);
     }
 ]
 /**
  * series 串行执行，依次执行
  * 第一个参数可以是一个数组也可以是一个JSON对象，参数类型不同，影响的是返回数据的格式
  */
// async.series(tasks1, function(err, results){
//   console.log(results);
// })

/**
 * waterfall 串行执行，依次执行
 * tasks参数只能是数组类型。
 * 将返回值传递给发一个执行函数
 */

// async.waterfall(
//   [
//     function(callback) {
//       callback(null, 'one', 'two');
//     },
//     function(arg1, arg2, callback) {
//       // arg1 now equals 'one' and arg2 now equals 'two'
//       callback(null, [arg1, arg2, 'three']);
//     },
//     function(arg1, callback) {
//       // arg1 now equals 'three'
//       callback(null, [...arg1, 'done']);
//     }
//   ],
//   function(err, result) {
//     // result now equals 'done'
//     console.log('err',err)
//     console.log(result);
//   }
// )

/**
 * parallel
 * 并行执行，参数跟series一样
 */
// const tasks2 = [
//   function (callback) {
//     setTimeout(function () {
//       callback(null, 1);
//     }, 1000);
//   },
//   function (callback) {
//     setTimeout(function () {
//       callback(null, 2);
//     }, 1000);
//   },
// ];
// console.time('parallel');
// async.parallel(tasks2, function(err, results) {
//   console.log(results);
//   console.timeEnd('parallel');
// })

/**
 * parallelLimit
 * 并行执行，limit 限制并发个数
 */
// async.parallelLimit(tasks2, 1,function(err, results) {
//   console.log(results);
//   console.timeEnd('parallel');
// })

/**
 * whilst(test, iterator, callback)
 * test: 条件函数 返回值得用callback
 * iterator：核心函数
 * callback： count返回false时触发回调
 * 
 * 当前循环的异步完成，才会进入下一个循环
 * callback所有循环结束时执行
 */
// var list = [{name:'Jack',age:20},{name:'Lucy',age:18}];
// var count = 0;
// async.whilst(
//   (cb) => cb(null, count < list.length),
//   (cb) => {
//     list[count++].age++;
//     cb(null, list);
//   },
//   (err) => {
//     console.log('done', err, list);
//   }
// )

/**
 * doWhilst(iterator, test, callback)
 * 先执行一次，再判断
 * 注意第二函数的参数 test(..arg, cb) ...arg是当前循环iterator cb中的结果
 */

// async.doWhilst(
//   (cb) => {
//     console.log('do it', count);
//     if (count < list.length) {
//       list[count].age++;
//       count++;
//     }
//     cb(null, 'hi');
//   },
//   (data,cb) => {
//     console.log('count', count < list.length, data);
//     cb(null, count < list.length);
//   },
//   (err) => {
//     console.log('done', err, list);
//   }
// );

/**
 * until(test, fn, callback)
 * 与whilst参数和执行逻辑相似
 * test 返回值是true跳出执行callback
 */
// async.until(
//   (cb) => cb(null, count>=list.length),
//   (cb) => {
//     setTimeout(() => {
//       console.log('do it');
//       list[count++].age++;
//       cb(null, list);
//     }, 1000)
//   },
//   (err) =>  {
//     console.log('done', err, list);
//   }
// )

/**
 * doUntil
 * 跟doWhilst相似
 * test返回值是true跳出执行callback
 */

// async.doUntil(
//   (cb) => setTimeout(()=>{
//     console.log('do it');
//     list[count++].age++;
//     cb(null, list);
//   }, 1000),
//   (data, cb) => cb(null, count >= list.length),
//   (err) => {
//     console.log('done', err, list);
//   }
// )

/**
 * forever(fn, errback)
 * 无论条件如何，函数都一直循环执行
 * 程序执行的过程中出现错误时循环才会停止，callback才会被调用
 */
// const runner = [null, null, null, null, '哎呀！出错啦'];
// let count = 0;
// async.forever(
//   (cb) => setTimeout(() => {
//     console.log('do it');
//     cb(runner[count++], runner[count]);
//   }, 1000),
//   (err, data) => {
//     console.log('done', err, data);
//   },
// )
/**
 * compose(fn1, fn2...);
 * 将异步函数组合从后往前依次执行，返回值传递给下一个
 * compose把异步函数f、g、h，组合成f(g(h()))的形式，通过callback得到返回值
 */
// console.time('t')

// function fn1(n, callback) {
//     setTimeout(function () {
//       console.log('do fn1', n);
//         callback(null, n + 1); //5
//     }, 1000);
// }

// function fn2(n, callback) {
//   console.log('do fn2', n);
//     setTimeout(function () {
//         callback(null, n * 3);
//     }, 1000);
// }

// var demo = async.compose(fn2, fn1);

// demo(4, function (err, result){
// 	console.log('done', err, result)
//     console.timeEnd('t')
// })

/**
 * auto(tasks, [callback])
 * callback返回所有tasks回调的结果
 * 处理有依赖关系的多个任务的执行
 * 依赖表示： taskname: ['otherTask', 'anotherTask2', function(result, callback){}]
 * 'otherTask', 'anotherTask2'依赖项；
 * function(result, callback){} 回调
 * result 是依赖项的返回值组成的对象
 * 
 */
//writeFile依赖getData和makeFolder,emailLink依赖writeFile
// async.auto(
//   {
//     get_data: function (callback) {
//       console.log('do get_data');
//       callback(null, 'data', 'converted to array');
//     },
//     make_folder: function (callback) {
//       console.log('do make_folder');
//       callback(null, 'folder'); //跟get_data同步执行
//     },
//     write_file: [
//       'get_data',
//       'make_folder',
//       function (results, callback) {
//         console.log('do write_file', results); //results是get_data和make_folder的返回值组成的对象
//         callback(null, 'filename');
//       },
//     ],
//     email_link: [
//       'write_file',
//       function (results, callback) {
//         console.log('do email_link', results);
//         callback(null, { file: results.write_file, email: 'user@example.com' });
//       },
//     ],
//   },
//   function (err, results) {
//     if (err) {
//       console.log('err = ', err);
//     }
//     console.log('results = ', results);
//   }
// );
/**
 * queue(worker, concurrency);
 * 相当于 parallelLimit;并行执行，limit 限制并发个数
 * 不再一次性全部执行
 * 当worker数量不够用时，新加入的任务将会排队等候，直到有新的worker可用
 * 
 *@params worker异步函数，处理队列中的每个tasks
 *@params concurrency限制队列里的tasks数量
 *@returns QueueObject 任务队列
 */
//创建一个大小是2的队列QueueObject
// const worker = () => {

// };

// const taskItem1 = {name: 'TaskItem1'};
// const taskItem2 = {name: 'TaskItem2'};
// const taskItem3 = {name: 'TaskItem3'};
// const taskItem4 = {name: 'TaskItem4'};

// const q = async.queue(worker, 2)
// q.push(taskItem1, err => {
//   console.log('finished processing taskItem1', err);
// });
// q.push(taskItem2, err => {
//   console.log('finished processing taskItem2', err);
// });
// q.push(taskItem3, err => {
//   console.log('finished processing taskItem3', err);
// });
// q.push(taskItem4, err => {
//   console.log('finished processing taskItem4', err);
// });
// q.push(taskItem1, err => {
//   console.log('finished processing taskItem1', err);
// });

/**
 * QueueObject 初步学习
 * @method push() 
 * @method empty() 最后一个任务交给worker执行时，会调用empty函数
 */

/**
 * apply(function, arguments..)
 * 给一个函数预绑定多个参数并生成一个可直接调用的新函数
 * 创建了一个偏函数
 */
/**
 * log是通过为console.log函数预设了一个参数'> '而得到的新函数，
 * 其输出格式为'> **'，
 * 请实现log函数，并调用它输出'> good';
 */

// const log = async.apply(console.log, '>');
// log('good');

/**
 * iterator(tasks)
 * 将一组函数包装成为一个iterator
 * 直接调用()，会执行当前函数，并返回一个由下个函数为起点的新的iterator
 * 调用next()，不会执行当前函数，直接返回由下个函数为起点的新iterator
 */
//v2可以正常运行
//v3 TypeError: async.iterator is not a function
const fnTasks = [
  function() {console.log('111')},
  function() {console.log('222')},
  function() {console.log('333')},
]
const it = async.iterator(fnTasks);
while(it) {
  it = it();
}
